package com.fingard.dsp.bank.directbank.cmb01;

import com.fingard.constant.Format;
import com.fingard.dsp.bank.directbank.bankInterface.ITransaction;
import com.fingard.dsp.bank.helpers.SeqRefundInfo;
import com.fingard.dsp.bank.helpers.SeqRefundInfoHelper;
import com.fingard.dsp.bank.reqrespobj.transaction.Req7515TodayTrans;
import com.fingard.dsp.bank.reqrespobj.transaction.Req7516HisTrans;
import com.fingard.dsp.bank.reqrespobj.transaction.RetAtsTrans;
import com.fingard.dsp.bank.reqrespobj.transaction.detail.RetAtsTransDetail;
import com.fingard.text.StringHelper;
import com.fingard.util.DateHelper;
import com.fingard.xml.XElement;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Date;
@Component("CMB01Transaction")
public class CMB01Transaction extends CMB01Base implements ITransaction {

    //采用流处理方式
    //1、循环调用readRecord()读取一个请求明细，然后写入发银行的XML对象
    //2、发银行
    //3、循环调用XmlTextReader.read()读取一个银行返回节点，赋值返回ATS的明细对象，
    //   然后调用writeRetDetail()，写入返回ATS的明细
    @Override
    public RetAtsTrans d_7516_HisTrans(Req7516HisTrans p_req7516) throws Exception {
        if ((StringHelper.hasAnyChar(p_req7516.higherLevelAct) && StringHelper.hasAnyChar(p_req7516.actNum)) || p_req7516.isVirtual) {
            return d_7516_HisTrans_NTDMTHLS(p_req7516);
        } else if (getBankConfig().getValueAsBool("useBreakpointTrans")) {
            return d_7516_HisTrans_GetTransInfoEX(p_req7516);
        } else {
            return d_7516_HisTrans_GetTransInfo(p_req7516);
        }
    }

    public RetAtsTrans d_7515_TodayTrans(Req7515TodayTrans p_req7515) throws Exception {
        if ((StringHelper.hasAnyChar(p_req7515.higherLevelAct) && StringHelper.hasAnyChar(p_req7515.actNum)) || p_req7515.isVirtual) {
            return d_7515_TodayTrans_NTDMTLST(p_req7515);
        } else {
            return d_7515_TodayTrans_GetTransInfo(p_req7515);
        }
    }

    public RetAtsTrans d_7516_HisTrans_GetTransInfo(Req7516HisTrans p_req7516) throws Exception {
        //历史明细查询返回ATS的对象
        RetAtsTrans retAts = new RetAtsTrans(p_req7516.reqHeader);
        String tmpRespCode = "";
        String tmpRespInfo = "";
        retAts.writeStart();//写返回ATS的统一头部信息
        SeqRefundInfoHelper seqRefundHelper = null;
        try {
            seqRefundHelper = new SeqRefundInfoHelper(p_req7516.reqHeader.tenant, p_req7516.reqHeader.getBusTime(new Date()));
            SeqRefundInfo refundInfo = new SeqRefundInfo();
            //tmpClndrStepTo.get(Calendar.MONTH) MONTH是从0开始编的，意味着0是1月，11是12月
            Calendar tmpCalendarFrom = Calendar.getInstance();
            tmpCalendarFrom.setTime(p_req7516.getDateFrom());

            Calendar tmpCalendarTo = Calendar.getInstance();
            tmpCalendarTo.setTime(p_req7516.getDateTo());

            int tmpIntDateFrom = 0;
            int tmpIntDateTo = 0;
            //按自然月循环查询
            while (tmpIntDateFrom <= tmpIntDateTo && tmpRespCode.length() == 0) {
                String isSetSleep = getBankConfig().getValueAsString("useSleepGetQuery");
                if ("true".equals(isSetSleep.toLowerCase())) {
                    int realSleepTime = getBankConfig().getValueAsInt("QuerySleepTime");
                    if (realSleepTime > 0) {
                        Date lastSleepGetQuery;
                        String keyLastSleep = "lastSleepGetQuery7516";
                        synchronized (bankFront.mutex7516) {
                            if (this.bankFront.customObjects.containsKey(keyLastSleep)) {
                                lastSleepGetQuery = (Date) bankFront.customObjects.get(keyLastSleep);
                                long diffMil = DateHelper.getDifferMilSecs(new Date(), lastSleepGetQuery);
                                long needSlpMil = realSleepTime * 1000;
                                long slpMil = needSlpMil - diffMil;
                                if (slpMil > 0) {
                                    this.WriteBankLogLn("等待" + slpMil + "毫秒");
                                    Thread.sleep(slpMil);
                                }
                                bankFront.putCustomObjects(keyLastSleep, new Date());
                            } else {
                                bankFront.putCustomObjects(keyLastSleep, new Date());
                            }
                        }
                    }
                }


                Calendar tmpClndrStepTo = Calendar.getInstance();
                tmpClndrStepTo.setTime(tmpCalendarFrom.getTime());
                //判断是否跨月
                if (DateHelper.compareMonth(tmpCalendarFrom, tmpCalendarTo) == -1) {
                    //跨月则设置为月末
                    tmpClndrStepTo.set(Calendar.DAY_OF_MONTH, tmpClndrStepTo.getActualMaximum(Calendar.DAY_OF_MONTH));
                } else {
                    tmpClndrStepTo.setTime(tmpCalendarTo.getTime());
                }
                CMB01Header tmpBnkHeader = new CMB01Header();
                tmpBnkHeader.FUNNAM = "GetTransInfo";
                XmlTextWriter xmlWriter = new XmlTextWriter();//发银行报文的XML对象
                writeCommonHeader(xmlWriter, tmpBnkHeader);
                xmlWriter.writeStartElement("SDKTSINFX");
                xmlWriter.writeElementString("BBKNBR", p_req7516.actArea);
                xmlWriter.writeElementClosed("C_BBKNBR");
                //主账户
                if (StringHelper.hasAnyChar(p_req7516.higherLevelAct)) {
                    xmlWriter.writeElementString("ACCNBR", p_req7516.higherLevelAct);
                } else {
                    xmlWriter.writeElementString("ACCNBR", p_req7516.actNum);
                }
                xmlWriter.writeElementString("BGNDAT", Format.Date8Format.format(tmpCalendarFrom.getTime()));
                xmlWriter.writeElementString("ENDDAT", Format.Date8Format.format(tmpClndrStepTo.getTime()));
                xmlWriter.writeElementClosed("LOWAMT");
                xmlWriter.writeElementClosed("HGHAMT");
                xmlWriter.writeElementClosed("AMTCDR");
                xmlWriter.writeEndDocument();

                String[] tmpStrRet = sendToBank(xmlWriter.toXmlString());

                if (tmpStrRet[0].length() == 0) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1], tmpSbMsg);
                    if (tmpBkReader != null) {
                        String tmpRETCOD = tmpBkReader.getFirstText("/CMBSDKPGK/INFO/RETCOD");
                        String tmpERRMSG = tmpBkReader.getFirstText("/CMBSDKPGK/INFO/ERRMSG");

                        if (tmpRETCOD != null) {

                            if ("0".equals(tmpRETCOD)) {

                                while (tmpBkReader.read("/CMBSDKPGK/NTQTSINFZ")) {
                                    //企业识别码
                                    String frmcod = tmpBkReader.readedXElement.getSingleText("FRMCOD");
                                    //上级账号不为空，发起二级账户流水查询，DSP通过现有实体账户查询接口获取流水，只需返回“企业识别码”值为对应二级账户的流水
                                    if (StringHelper.hasAnyChar(p_req7516.higherLevelAct)) {
                                        if (!p_req7516.actNum.equals(frmcod)) {
                                            continue;
                                        }
                                    } else {//上级账号为空，发起一级账户流水查询，DSP通过现有实体账户查询接口获取流水，只需返回“企业识别码”值为空的流水
                                        if (!StringHelper.isNullOrEmpty(frmcod)) {
                                            continue;
                                        }
                                    }
                                    RetAtsTransDetail tmpRetDetail = new RetAtsTransDetail();
                                    tmpRetDetail.actNum = p_req7516.actNum;
                                    tmpRetDetail.recAccBank = tmpBkReader.readedXElement.getSingleText("RPYBNK");
                                    tmpRetDetail.accBal = tmpBkReader.readedXElement.getSingleText("TRSBLV");
                                    tmpRetDetail.recAccNum = tmpBkReader.readedXElement.getSingleText("RPYACC");
                                    if (StringHelper.isNullOrEmpty(tmpRetDetail.recAccNum)) {
                                        tmpRetDetail.recAccNum = tmpBkReader.readedXElement.getSingleText("GSBACC");
                                    }
                                    tmpRetDetail.recAccName = tmpBkReader.readedXElement.getSingleText("RPYNAM");
                                    if (StringHelper.isNullOrEmpty(tmpRetDetail.recAccName)) {
                                        tmpRetDetail.recAccName = tmpBkReader.readedXElement.getSingleText("GSBNAM");
                                    }
                                    //AMTCDR	借贷标记	C（1）	C:贷；D:借
                                    String tmpAMTCDR = tmpBkReader.readedXElement.getSingleText("AMTCDR");
                                    //String tmpTRSAMTD = tmpBkReader.readedXElement.getSingleText("TRSAMTD");
                                    if (tmpAMTCDR.equals("D")) {
                                        tmpRetDetail.tranAmt = tmpBkReader.readedXElement.getSingleText("TRSAMTD");
                                        tmpRetDetail.cdFlag = "1";
                                    } else if (tmpAMTCDR.equals("C")) {
                                        tmpRetDetail.tranAmt = tmpBkReader.readedXElement.getSingleText("TRSAMTC");
                                        tmpRetDetail.cdFlag = "2";
                                    } else {
                                        throw new Exception("无效的AMTCDR借贷标记：" + tmpAMTCDR);
                                    }
                                    String tmpETYDAT = tmpBkReader.readedXElement.getSingleText("ETYDAT");
                                    if (tmpETYDAT.length() == 8) {
                                        tmpRetDetail.tranDate = tmpETYDAT.substring(0, 4) + "-" + tmpETYDAT.substring(4, 6) + "-" + tmpETYDAT.substring(6, 8);
                                    } else {
                                        tmpRetDetail.tranDate = tmpETYDAT;
                                    }
                                    String tmpETYTIM = tmpBkReader.readedXElement.getSingleText("ETYTIM");
                                    if (tmpETYTIM.length() == 6) {
                                        tmpRetDetail.tranTime = tmpRetDetail.tranDate + " " + tmpETYTIM.substring(0, 2) + ":" + tmpETYTIM.substring(2, 4) + ":" + tmpETYTIM.substring(4, 6);
                                    } else {
                                        tmpRetDetail.tranTime = tmpRetDetail.tranDate + " " + tmpETYTIM;
                                    }
                                    String tmpVLTDAT = tmpBkReader.readedXElement.getSingleText("RLTDAT");
                                    if (tmpVLTDAT != null && tmpVLTDAT.length() == 6) {
                                        tmpRetDetail.valueDate = tmpVLTDAT.substring(0, 4) + "-" + tmpVLTDAT.substring(4, 6) + "-" + tmpVLTDAT.substring(6, 8);
                                    } else {
                                        tmpRetDetail.valueDate = tmpRetDetail.tranDate;
                                    }
                                    String billTypeCode = tmpBkReader.readedXElement.getSingleText("TRSCOD");
                                    tmpRetDetail.billType = billTypeCode;
                                    if (getBankConfig().getValueAsBool("billTypeMapping")) {
                                        String billType = this.convertBillTypeToBank(tmpRetDetail.billType);
                                        if (!StringHelper.isNullOrEmpty(billType)) {
                                            tmpRetDetail.billType = billTypeCode + "-" + billType;
                                        }
                                    }
                                    tmpRetDetail.billNum = tmpBkReader.readedXElement.getSingleText("CHKNBR");
                                    tmpRetDetail.usage = tmpBkReader.readedXElement.getSingleText("NARYUR");
                                    if (StringHelper.isNullOrEmpty(tmpRetDetail.usage)) {
                                        tmpRetDetail.usage = tmpBkReader.readedXElement.getSingleText("NUSAGE");
                                    }
                                    tmpRetDetail.payCode = StringHelper.joinNotEmpty("+", tmpBkReader.readedXElement.getSingleText("REQNBR"), tmpBkReader.readedXElement.getSingleText("BUSNAR"));
                                    if (getBankConfig().getValueAsBool("fixPayCode")) {
                                        tmpRetDetail.payCode = tmpBkReader.readedXElement.getSingleText("REFNBR");
                                    }
                                    tmpRetDetail.askNumber = tmpBkReader.readedXElement.getSingleText("YURREF");
                                    tmpRetDetail.originator = tmpBkReader.readedXElement.getSingleText("REFNBR");
                                    tmpRetDetail.comment = tmpBkReader.readedXElement.getSingleText("NARYUR");
                                    tmpRetDetail.abstr = pickupAbstr(tmpBkReader.readedXElement.getSingleText("BUSNAR"), tmpBkReader.readedXElement.getSingleText("NARYUR"), tmpBkReader.readedXElement.getSingleText("YURREF"));
                                    tmpRetDetail.postTimestamp = tmpBkReader.readedXElement.getSingleText("ETYDAT") + tmpBkReader.readedXElement.getSingleText("REFNBR");

                                    String[] busrefs = new String[4];
                                    busrefs[0] = tmpBkReader.readedXElement.getSingleText("REFNBR");
                                    busrefs[1] = tmpBkReader.readedXElement.getSingleText("NAREXT");
                                    busrefs[2] = tmpBkReader.readedXElement.getSingleText("REQNBR");
                                    busrefs[3] = tmpBkReader.readedXElement.getSingleText("YURREF");

                                    String bnkSeqNo = tmpBkReader.readedXElement.getSingleText("REFNBR");
                                    tmpRetDetail.bnkSeqNo = StringHelper.hasAnyChar(bnkSeqNo) ? bnkSeqNo : tmpBkReader.readedXElement.getSingleText("REQNBR");

                                    tmpRetDetail.receiptNo = StringHelper.getFirstNotEmptyTrim(busrefs);
                                    tmpRetDetail.busRef = StringHelper.joinNotEmpty(",", busrefs).replace(tmpRetDetail.receiptNo + ",", "");

                                    refundInfo = seqRefundHelper.loadFromDb(p_req7516.reqHeader.bankCode, tmpRetDetail.askNumber);
                                    if (refundInfo != null) {
                                        tmpRetDetail.comment = refundInfo.refundTicketReason;
                                    }
                                    nodeAnalysic(tmpBkReader.readedXElement, tmpRetDetail, getCharset());
                                    retAts.writeRetDetail(tmpRetDetail);
                                }
                            }
                        } else {
                            tmpRespCode = "-1";
                            tmpRespInfo = tmpERRMSG;
                            break;
                        }
                    } else {

                        tmpRespCode = "-1";
                        tmpRespInfo = tmpSbMsg.toString();
                        break;
                    }
                } else {
                    tmpRespCode = "-1";
                    tmpRespInfo = tmpStrRet[1];
                    break;
                }
                tmpCalendarFrom = tmpClndrStepTo;
                tmpCalendarFrom.add(Calendar.DAY_OF_MONTH, 1);
                tmpIntDateFrom = Integer.parseInt(Format.Date8Format.format(tmpCalendarFrom.getTime()));
                tmpIntDateTo = Integer.parseInt(Format.Date8Format.format(tmpCalendarTo.getTime()));
            }
        } catch (Exception e) {
            tmpRespCode = "-1";
            tmpRespInfo = e.getMessage();
            e.printStackTrace();
        }
        if (tmpRespCode.equals("-1")) {
            retAts = new RetAtsTrans(p_req7516.reqHeader);
            retAts.writeStart();//写返回ATS的统一头部信息
            retAts.writeRespCode(tmpRespCode);
            retAts.writeRespInfo(tmpRespInfo);
        } else if (retAts.getWrittenRdCount() == 0) {
            retAts.writeRespCode("0");
            retAts.writeRespInfo("交易为空");
        }
        retAts.writeEnd();
        return retAts;
    }

    //当日明细查询调用历史明细查询方法
    public RetAtsTrans d_7515_TodayTrans_GetTransInfo(Req7515TodayTrans p_req7515) throws Exception {
        //通用b2e0035
        Req7516HisTrans tmpReq7516 = new Req7516HisTrans(p_req7515.reqHeader);
        tmpReq7516.actArea = p_req7515.actArea;
        tmpReq7516.actCur = p_req7515.actCur;
        tmpReq7516.actNum = p_req7515.actNum;
        String tmpStrToday = Format.Date8Format.format(new Date());
        tmpReq7516.dateFrom = tmpStrToday;
        tmpReq7516.dateTo = tmpStrToday;
        tmpReq7516.higherLevelAct = p_req7515.higherLevelAct;
        if (getBankConfig().getValueAsBool("useGetTransInfoEX7515")) {
            return d_7516_HisTrans_GetTransInfoEX(tmpReq7516);
        } else {
            return d_7516_HisTrans_GetTransInfo(tmpReq7516);
        }
    }

    /**
     * 历史明细
     *
     * @param p_req7516
     * @return
     * @throws Exception
     */
    public RetAtsTrans d_7516_HisTrans_NTDMTHLS(Req7516HisTrans p_req7516) throws Exception {
        //增加历史明细支持查询日期
        if (StringHelper.hasAnyChar(getBankConfig().getValueAsString("hisTransSupDate"))
                && getBankConfig().getValueAsString("hisTransSupDate").length() == 8) {
            //判断起始日
            Date avaiDate = Format.Date8Format.parse(getBankConfig().getValueAsString("hisTransSupDate"));
            Date startDate = Format.Date8Format.parse(p_req7516.dateFrom);
            Date endDate = Format.Date8Format.parse(p_req7516.dateTo);
            if (endDate.after(avaiDate)) {
                if (startDate.before(avaiDate)) {
                    p_req7516.dateFrom = getBankConfig().getValueAsString("hisTransSupDate");
                }
            } else {
                p_req7516.dateFrom = getBankConfig().getValueAsString("hisTransSupDate");
                p_req7516.dateTo = getBankConfig().getValueAsString("hisTransSupDate");
            }
        }
        RetAtsTrans retAtsTrans = new RetAtsTrans(p_req7516.reqHeader);
        retAtsTrans.writeStart();
        String tmpRespCode = "";
        String tmpRespInfo = "";
        try {
            //起始日期
            Calendar tmpCalendarFrom = Calendar.getInstance();
            tmpCalendarFrom.setTime(p_req7516.getDateFrom());
            //结束日期
            Calendar tmpCalendarTo = Calendar.getInstance();
            tmpCalendarTo.setTime(p_req7516.getDateTo());
            //明细按月查询，有些银行不支持跨月查询
            int tmpIntDateFrom = 0;
            int tmpIntDateTo = 0;
            while (tmpIntDateFrom <= tmpIntDateTo && StringHelper.isNullOrEmpty(tmpRespCode)) {
                String isSetSleep = getBankConfig().getValueAsString("useSleepGetQuery");
                if ("true".equals(isSetSleep.toLowerCase())) {
                    long realSleepTime = getBankConfig().getValueAsInt("QuerySleepTime");
                    if (realSleepTime < 0) {
                        realSleepTime = 0;
                    }
                    Thread.sleep(realSleepTime * 1000);
                }
                Calendar tmpClndrStepTo = Calendar.getInstance();
                tmpClndrStepTo.setTime(tmpCalendarFrom.getTime());
                //当是跨月查询时，先查询起始日期到月末日期记录，再查询月末后一天日期到结束日期记录
                if (DateHelper.compareMonth(tmpCalendarFrom, tmpCalendarTo) == -1) {//起始日期月份小于结束日期月份，表示跨月
                    tmpClndrStepTo.set(Calendar.DAY_OF_MONTH, tmpClndrStepTo.getActualMaximum(Calendar.DAY_OF_MONTH));//获取月末日期
                } else {
                    tmpClndrStepTo.setTime(tmpCalendarTo.getTime());
                }
                //拼接报文
                //拼接请求报文头
                CMB01Header tmpBnkHeader = new CMB01Header();
                if ("7516".equals(p_req7516.reqHeader.transType)) {
                    tmpBnkHeader.FUNNAM = "NTDMTHLS";
                } else {
                    tmpBnkHeader.FUNNAM = "NTDMTLST";
                }
                XmlTextWriter xmlTextWriter = new XmlTextWriter();
                //非公有参数
                writeCommonHeader(xmlTextWriter, tmpBnkHeader);
                //拼接请求报文体
                if ("7516".equals(p_req7516.reqHeader.transType)) {
                    xmlTextWriter.writeStartElement("NTDMTHLSY");
                } else {
                    xmlTextWriter.writeStartElement("NTDMTLSTY");
                }
                //主账户
                String higherLevelAct = p_req7516.higherLevelAct;
                if(StringHelper.isNullOrEmpty(higherLevelAct)){
                    higherLevelAct = this.getBankConfig().getMapValueByKey("higherLevelAct",p_req7516.actNum);
                }
                if (StringHelper.hasAnyChar(higherLevelAct)) {
                    xmlTextWriter.writeElementString("ACCNBR", higherLevelAct);//主体账户
                } else {
                    tmpRespCode = "-1";
                    tmpRespInfo = "请求报文中ACCNBR节点为空，请检查CMB01/config.xml中'higherLevelAct'节点配置";
                    retAtsTrans.writeRespCode(tmpRespCode);
                    retAtsTrans.writeRespInfo(tmpRespInfo);
                    retAtsTrans.writeEnd();
                    return retAtsTrans;
                }
                String virtualNo = p_req7516.actNum.replace(higherLevelAct, "");
                xmlTextWriter.writeElementString("DMANBR", virtualNo);//虚拟户编号
                if ("7516".equals(p_req7516.reqHeader.transType)) {
                    xmlTextWriter.writeElementString("BEGDAT", Format.Date8Format.format(tmpCalendarFrom.getTime()));//该日期为账户时区的当日日期
                    xmlTextWriter.writeElementString("ENDDAT", Format.Date8Format.format(tmpClndrStepTo.getTime()));//该日期为输入日期
                }
                xmlTextWriter.writeEndElement();
                xmlTextWriter.writeEndDocument();
                //发送请求报文
                String[] resutlt = sendToBank(xmlTextWriter.toXmlString());

                //处理响应报文
                if (resutlt[0].length() == 0) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(resutlt[1].trim(), tmpSbMsg);
                    if (tmpBkReader != null) {
                        String respCode = tmpBkReader.getFirstText("/CMBSDKPGK/INFO/RETCOD").trim();//返回码
                        String respInfo = tmpBkReader.getFirstText("/CMBSDKPGK/INFO/ERRMSG");//返回信息
                        if ("0".equals(respCode)) {
                            String tmpStr = "";
                            if ("7516".equals(p_req7516.reqHeader.transType)) {
                                tmpStr = "/CMBSDKPGK/NTDMTHLSZ";
                            } else {
                                tmpStr = "/CMBSDKPGK/NTDMTLSTZ";
                            }
                            while (tmpBkReader.read(tmpStr)) {
                                XElement readXElement = tmpBkReader.readedXElement;
                                RetAtsTransDetail tmpRetDetail = new RetAtsTransDetail();
                                tmpRetDetail.actNum = p_req7516.actNum;//银行账号
                                tmpRetDetail.askNumber = readXElement.getSingleTextNotNull("TRXNBR"); //记账流水号
                                tmpRetDetail.originator = readXElement.getSingleTextNotNull("TRXNBR"); //记账流水号
                                tmpRetDetail.cur = convertCurToATS(readXElement.getSingleTextNotNull("CCYNBR"));//币种
                                //AMTCDR	借贷标记	C（1）	C:贷；D:借
                                String tmpAMTCDR = tmpBkReader.readedXElement.getSingleText("TRXDIR");
                                if (tmpAMTCDR.equals("D")) {
                                    tmpRetDetail.tranAmt = tmpBkReader.readedXElement.getSingleText("TRXAMT").replace("-", "");
                                    tmpRetDetail.cdFlag = "1";
                                } else if (tmpAMTCDR.equals("C")) {
                                    tmpRetDetail.tranAmt = tmpBkReader.readedXElement.getSingleText("TRXAMT").replace("-", "");
                                    tmpRetDetail.cdFlag = "2";
                                } else {
                                    throw new Exception("无效的AMTCDR借贷标记：" + tmpAMTCDR);
                                }
                                tmpRetDetail.recAccBank = tmpBkReader.readedXElement.getSingleText("RPYBNK");
                                tmpRetDetail.accBal = tmpBkReader.readedXElement.getSingleText("TRSBLV");
                                tmpRetDetail.recAccNum = tmpBkReader.readedXElement.getSingleText("RPYACC");
                                tmpRetDetail.recAccName = tmpBkReader.readedXElement.getSingleText("RPYNAM");
                                String tmpETYDAT = tmpBkReader.readedXElement.getSingleText("TRXDAT");
                                if (tmpETYDAT.length() == 8) {
                                    tmpRetDetail.tranDate = tmpETYDAT.substring(0, 4) + "-" + tmpETYDAT.substring(4, 6) + "-" + tmpETYDAT.substring(6, 8);
                                } else {
                                    tmpRetDetail.tranDate = tmpETYDAT;
                                }
                                if (!StringHelper.hasAnyChar(tmpRetDetail.tranDate)) {
                                    tmpRetDetail.tranDate = Format.Date10Format.format(new Date());
                                }
                                tmpRetDetail.valueDate = tmpRetDetail.tranDate;
                                String tmpETYTIM = tmpBkReader.readedXElement.getSingleText("TRXTIM");
                                if (tmpETYTIM.length() == 6) {
                                    tmpRetDetail.tranTime = tmpRetDetail.tranDate + " " + tmpETYTIM.substring(0, 2) + ":" + tmpETYTIM.substring(2, 4) + ":" + tmpETYTIM.substring(4, 6);
                                } else {
                                    tmpRetDetail.tranTime = tmpRetDetail.tranDate + " " + tmpETYTIM;
                                }
                                String billTypeCode = tmpBkReader.readedXElement.getSingleText("TRSCOD");
                                tmpRetDetail.billType = billTypeCode;
                                if (getBankConfig().getValueAsBool("billTypeMapping")) {
                                    String billType = this.convertBillTypeToBank(tmpRetDetail.billType);
                                    if (!StringHelper.isNullOrEmpty(billType)) {
                                        tmpRetDetail.billType = billTypeCode + "-" + billType;
                                    }
                                }
                                tmpRetDetail.billNum = tmpBkReader.readedXElement.getSingleText("CHKNBR");

                                String tmpAbstr = StringHelper.convertToDBC(tmpBkReader.readedXElement.getSingleText("TRXTXT"));
                                tmpRetDetail.usage = "false".equalsIgnoreCase(getBankConfig().getValueAsString("TransUsageConvertToDBC")) ? tmpRetDetail.usage : tmpAbstr;
                                if (StringHelper.hasAnyChar(tmpRetDetail.usage) && tmpRetDetail.usage.indexOf(";") > 0) {
                                    //<Usage>20190423;20190423</Usage>
                                    String[] spVals = tmpRetDetail.usage.split(";");
                                    if (spVals.length == 2 && spVals[0].equals(spVals[1])) {
                                        tmpRetDetail.usage = spVals[0];
                                    }
                                }
                                tmpRetDetail.receiptNo = tmpBkReader.readedXElement.getSingleText("TRXNBR");
                                tmpRetDetail.busRef = tmpBkReader.readedXElement.getSingleText("NARINN");
                                tmpRetDetail.bnkSeqNo = tmpBkReader.readedXElement.getSingleText("REQNBR");

                                /*String abstr = "方海洪+33455678987654";
                                tmpRetDetail.abstr = pickupAbstr(abstr);*/
                                nodeAnalysic(tmpBkReader.readedXElement, tmpRetDetail, getCharset());
                                retAtsTrans.writeRetDetail(tmpRetDetail);
                            }
                        } else {
                            tmpRespInfo = respInfo;
                            WriteBankLogLn("查询失败：" + respInfo);
                        }
                    }
                } else {
                    tmpRespCode = "-1";
                    tmpRespInfo = resutlt[1];
                    break;
                }
                tmpCalendarFrom = tmpClndrStepTo;
                tmpCalendarFrom.add(Calendar.DAY_OF_MONTH, 1);//月末后一天日期
                tmpIntDateFrom = Integer.parseInt(Format.Date8Format.format(tmpCalendarFrom.getTime()));
                tmpIntDateTo = Integer.parseInt(Format.Date8Format.format(tmpCalendarTo.getTime()));
            }
        } catch (Exception ex) {
            tmpRespCode = "-1";
            tmpRespInfo = ex.getMessage();
            ex.printStackTrace();
            WriteBankLogLn("查询明细异常:" + ex);
        }
        if ("-1".equals(tmpRespCode)) {
            retAtsTrans = new RetAtsTrans(p_req7516.reqHeader);
            retAtsTrans.writeStart();//写返回ATS的统一头部信息
            retAtsTrans.writeRespCode(tmpRespCode);
            retAtsTrans.writeRespInfo(tmpRespInfo);
        } else if (retAtsTrans.getWrittenRdCount() == 0) {
            retAtsTrans.writeRespInfo("交易为空");
            retAtsTrans.writeRespCode("0");
        }
        retAtsTrans.writeEnd();
        return retAtsTrans;
    }

    /**
     * 今日明细
     *
     * @param p_req7515
     * @return
     * @throws Exception
     */
    public RetAtsTrans d_7515_TodayTrans_NTDMTLST(Req7515TodayTrans p_req7515) throws Exception {
        Req7516HisTrans tmpReq7516 = new Req7516HisTrans(p_req7515.reqHeader);
        tmpReq7516.actArea = p_req7515.actArea;
        tmpReq7516.actCur = p_req7515.actCur;
        tmpReq7516.actNum = p_req7515.actNum;
//            备注:现场测试招行填写招行固定测试服务器日期时使用,需在config.xml中增加配置节点:<TestDate>20191028</TestDate>
//            Date bgnDate = Format.Date8Format.parse(getBankConfig().getValueAsString("TestDate"));
        String tmpStrToday = Format.Date8Format.format(new Date());
        tmpReq7516.dateFrom = tmpStrToday;
        tmpReq7516.dateTo = tmpStrToday;
        tmpReq7516.higherLevelAct = p_req7515.higherLevelAct;
        return d_7516_HisTrans_NTDMTHLS(tmpReq7516);
    }

    /**
     * 参考文档：https://u.ebank.cmbchina.com/CmbBank_GenShell/UI/Help/DCBank2/API.aspx?02ZHGL/04GetTransInfoEX
     * <p>
     * 章节 2.4 账户交易信息断点查询
     */
    public RetAtsTrans d_7516_HisTrans_GetTransInfoEX(Req7516HisTrans p_req7516) throws Exception {
        //历史明细查询返回ATS的对象
        RetAtsTrans retAts = new RetAtsTrans(p_req7516.reqHeader);
        String tmpRespCode = "";
        String tmpRespInfo = "";
        retAts.writeStart();//写返回ATS的统一头部信息
        try {
            Calendar tmpCalendarFrom = Calendar.getInstance();
            tmpCalendarFrom.setTime(p_req7516.getDateFrom());

            Calendar tmpCalendarTo = Calendar.getInstance();
            tmpCalendarTo.setTime(p_req7516.getDateTo());

            int tmpIntDateFrom = 0;
            int tmpIntDateTo = 0;
            int trsseq = 0;//起始记账序号
            String cotflg = "";
            //按自然月循环查询
            while (tmpIntDateFrom <= tmpIntDateTo && tmpRespCode.length() == 0) {
            	/*
                String isSetSleep = getBankConfig().getValueAsString("useSleepGetQuery");
                if ("true".equals(isSetSleep.toLowerCase())) {
                    long realSleepTime = getBankConfig().getValueAsInt("QuerySleepTime");
                    if (realSleepTime < 0) {
                        realSleepTime = 0;
                    }
                    Thread.sleep(realSleepTime * 1000);
                }
                */
                Calendar tmpClndrStepTo = Calendar.getInstance();
                tmpClndrStepTo.setTime(tmpCalendarFrom.getTime());
                //判断是否跨月
                if (DateHelper.compareMonth(tmpCalendarFrom, tmpCalendarTo) == -1) {
                    //跨月则设置为月末
                    tmpClndrStepTo.set(Calendar.DAY_OF_MONTH, tmpClndrStepTo.getActualMaximum(Calendar.DAY_OF_MONTH));
                } else {
                    tmpClndrStepTo.setTime(tmpCalendarTo.getTime());
                }
                CMB01Header tmpBnkHeader = new CMB01Header();
                tmpBnkHeader.FUNNAM = "GetTransInfoEX";
                XmlTextWriter xmlWriter = new XmlTextWriter();//发银行报文的XML对象
                writeCommonHeader(xmlWriter, tmpBnkHeader);
                xmlWriter.writeStartElement("SDKRBPTRSX");
                xmlWriter.writeElementString("BBKNBR", p_req7516.actArea);
                xmlWriter.writeElementClosed("C_BBKNBR");
                //主账户
                if (StringHelper.hasAnyChar(p_req7516.higherLevelAct)) {
                    xmlWriter.writeElementString("ACCNBR", p_req7516.higherLevelAct);
                } else {
                    xmlWriter.writeElementString("ACCNBR", p_req7516.actNum);
                }
                xmlWriter.writeElementString("TRSDAT", Format.Date8Format.format(tmpCalendarFrom.getTime()));
                xmlWriter.writeElementString("TRSSEQ", Integer.toString(trsseq));
                xmlWriter.writeEndDocument();

                String[] tmpStrRet = sendToBank(xmlWriter.toXmlString());

                if (tmpStrRet[0].length() == 0) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1], tmpSbMsg);
                    if (tmpBkReader != null) {
                        String tmpRETCOD = tmpBkReader.getFirstText("/CMBSDKPGK/INFO/RETCOD");
                        String tmpERRMSG = tmpBkReader.getFirstText("/CMBSDKPGK/INFO/ERRMSG");

                        if ("0".equals(tmpRETCOD)) {
                            cotflg = tmpBkReader.getFirstText("/CMBSDKPGK/NTRBPTRSZ1/COTFLG");
                            while (tmpBkReader.read("/CMBSDKPGK/NTQTSINFZ")) {
                                //企业识别码
                                String frmcod = tmpBkReader.readedXElement.getSingleText("FRMCOD");
                                //上级账号不为空，发起二级账户流水查询，DSP通过现有实体账户查询接口获取流水，只需返回“企业识别码”值为对应二级账户的流水
                                if (StringHelper.hasAnyChar(p_req7516.higherLevelAct)) {
                                    if (!p_req7516.actNum.equals(frmcod)) {
                                        continue;
                                    }
                                } else {//上级账号为空，发起一级账户流水查询，DSP通过现有实体账户查询接口获取流水，只需返回“企业识别码”值为空的流水
                                    if (!StringHelper.isNullOrEmpty(frmcod)) {
                                        continue;
                                    }
                                }
                                RetAtsTransDetail tmpRetDetail = new RetAtsTransDetail();
                                tmpRetDetail.actNum = p_req7516.actNum;
                                tmpRetDetail.recAccBank = tmpBkReader.readedXElement.getSingleText("RPYBNK");
                                tmpRetDetail.accBal = tmpBkReader.readedXElement.getSingleText("TRSBLV");
                                tmpRetDetail.recAccNum = tmpBkReader.readedXElement.getSingleText("RPYACC");
                                if (StringHelper.isNullOrEmpty(tmpRetDetail.recAccNum)) {
                                    tmpRetDetail.recAccNum = tmpBkReader.readedXElement.getSingleText("GSBACC");
                                }
                                tmpRetDetail.recAccName = tmpBkReader.readedXElement.getSingleText("RPYNAM");
                                if (StringHelper.isNullOrEmpty(tmpRetDetail.recAccName)) {
                                    tmpRetDetail.recAccName = tmpBkReader.readedXElement.getSingleText("GSBNAM");
                                }
                                //AMTCDR	借贷标记	C（1）	C:贷；D:借
                                String tmpAMTCDR = tmpBkReader.readedXElement.getSingleText("AMTCDR");
                                if (tmpAMTCDR.equals("D")) {
                                    tmpRetDetail.tranAmt = tmpBkReader.readedXElement.getSingleText("TRSAMTD");
                                    if (StringHelper.isNullOrEmpty(tmpRetDetail.tranAmt)) {
                                        tmpRetDetail.tranAmt = tmpBkReader.readedXElement.getSingleText("C_TRSAMTD");
                                    }
                                    tmpRetDetail.cdFlag = "1";
                                } else if (tmpAMTCDR.equals("C")) {
                                    tmpRetDetail.tranAmt = tmpBkReader.readedXElement.getSingleText("TRSAMTC");
                                    if (StringHelper.isNullOrEmpty(tmpRetDetail.tranAmt)) {
                                        tmpRetDetail.tranAmt = tmpBkReader.readedXElement.getSingleText("C_TRSAMTC");
                                    }
                                    tmpRetDetail.cdFlag = "2";
                                } else {
                                    throw new Exception("无效的AMTCDR借贷标记：" + tmpAMTCDR);
                                }
                                String tmpETYDAT = tmpBkReader.readedXElement.getSingleText("ETYDAT");
                                if (tmpETYDAT.length() == 8) {
                                    tmpRetDetail.tranDate = tmpETYDAT.substring(0, 4) + "-" + tmpETYDAT.substring(4, 6) + "-" + tmpETYDAT.substring(6, 8);
                                } else {
                                    tmpRetDetail.tranDate = tmpETYDAT;
                                }
                                String tmpETYTIM = tmpBkReader.readedXElement.getSingleText("ETYTIM");
                                if (tmpETYTIM.length() == 6) {
                                    tmpRetDetail.tranTime = tmpRetDetail.tranDate + " " + tmpETYTIM.substring(0, 2) + ":" + tmpETYTIM.substring(2, 4) + ":" + tmpETYTIM.substring(4, 6);
                                } else {
                                    tmpRetDetail.tranTime = tmpRetDetail.tranDate + " " + tmpETYTIM;
                                }
                                String tmpVLTDAT = tmpBkReader.readedXElement.getSingleText("RLTDAT");
                                if (tmpVLTDAT != null && tmpVLTDAT.length() == 6) {
                                    tmpRetDetail.valueDate = tmpVLTDAT.substring(0, 4) + "-" + tmpVLTDAT.substring(4, 6) + "-" + tmpVLTDAT.substring(6, 8);
                                } else {
                                    tmpRetDetail.valueDate = tmpRetDetail.tranDate;
                                }
                                String billTypeCode = tmpBkReader.readedXElement.getSingleText("TRSCOD");
                                tmpRetDetail.billType = billTypeCode;
                                if (getBankConfig().getValueAsBool("billTypeMapping")) {
                                    String billType = this.convertBillTypeToBank(tmpRetDetail.billType);
                                    if (!StringHelper.isNullOrEmpty(billType)) {
                                        tmpRetDetail.billType = billTypeCode + "-" + billType;
                                    }
                                }
                                tmpRetDetail.billNum = tmpBkReader.readedXElement.getSingleText("CHKNBR");
                                tmpRetDetail.usage = tmpBkReader.readedXElement.getSingleText("NARYUR");
                                if (StringHelper.isNullOrEmpty(tmpRetDetail.usage)) {
                                    tmpRetDetail.usage = tmpBkReader.readedXElement.getSingleText("NUSAGE");
                                }
                                tmpRetDetail.payCode = StringHelper.joinNotEmpty("+", tmpBkReader.readedXElement.getSingleText("REQNBR"), tmpBkReader.readedXElement.getSingleText("BUSNAR"));
                                if (getBankConfig().getValueAsBool("fixPayCode")) {
                                    tmpRetDetail.payCode = tmpBkReader.readedXElement.getSingleText("REFNBR");
                                }
                                tmpRetDetail.askNumber = tmpBkReader.readedXElement.getSingleText("YURREF");
                                tmpRetDetail.originator = tmpBkReader.readedXElement.getSingleText("REFNBR");
                                tmpRetDetail.comment = tmpBkReader.readedXElement.getSingleText("NARYUR");
                                tmpRetDetail.abstr = pickupAbstr(tmpBkReader.readedXElement.getSingleText("BUSNAR"), tmpBkReader.readedXElement.getSingleText("NARYUR"), tmpBkReader.readedXElement.getSingleText("YURREF"));
                                tmpRetDetail.postTimestamp = tmpBkReader.readedXElement.getSingleText("ETYDAT") + tmpBkReader.readedXElement.getSingleText("REFNBR");

                                String[] busrefs = new String[4];
                                busrefs[0] = tmpBkReader.readedXElement.getSingleText("REFNBR");
                                busrefs[1] = tmpBkReader.readedXElement.getSingleText("NAREXT");
                                busrefs[2] = tmpBkReader.readedXElement.getSingleText("REQNBR");
                                busrefs[3] = tmpBkReader.readedXElement.getSingleText("YURREF");

                                tmpRetDetail.bnkSeqNo = tmpBkReader.readedXElement.getSingleText("REQNBR");
                                tmpRetDetail.receiptNo = StringHelper.getFirstNotEmptyTrim(busrefs);
                                tmpRetDetail.busRef = StringHelper.joinNotEmpty(",", busrefs).replace(tmpRetDetail.receiptNo + ",", "");

                                nodeAnalysic(tmpBkReader.readedXElement, tmpRetDetail, getCharset());
                                retAts.writeRetDetail(tmpRetDetail);
                            }
                        } else {
                            tmpRespCode = "-1";
                            tmpRespInfo = tmpERRMSG;
                            break;
                        }
                    } else {

                        tmpRespCode = "-1";
                        tmpRespInfo = tmpSbMsg.toString();
                        break;
                    }
                } else {
                    tmpRespCode = "-1";
                    tmpRespInfo = tmpStrRet[1];
                    break;
                }
                if ("N".equals(cotflg)) {
                    trsseq = 0;
//                    tmpCalendarFrom = tmpClndrStepTo;
                    tmpCalendarFrom.add(Calendar.DAY_OF_MONTH, 1);
                    tmpIntDateFrom = Integer.parseInt(Format.Date8Format.format(tmpCalendarFrom.getTime()));
                    tmpIntDateTo = Integer.parseInt(Format.Date8Format.format(tmpCalendarTo.getTime()));
                } else if ("Y".equals(cotflg)) {
                    trsseq++;
                    tmpIntDateFrom = Integer.parseInt(Format.Date8Format.format(tmpCalendarFrom.getTime()));
                    tmpIntDateTo = Integer.parseInt(Format.Date8Format.format(tmpCalendarTo.getTime()));
                } else {
                    tmpRespCode = "-1";
                    tmpRespInfo = "银行返回的COTFLG节点值既不是'Y'也不是'N'，请咨询银行人员";
                    break;
                }
            }
        } catch (Exception e) {
            tmpRespCode = "-1";
            tmpRespInfo = e.getMessage();
            e.printStackTrace();
        }
        if (tmpRespCode.equals("-1")) {
            retAts = new RetAtsTrans(p_req7516.reqHeader);
            retAts.writeStart();//写返回ATS的统一头部信息
            retAts.writeRespCode(tmpRespCode);
            retAts.writeRespInfo(tmpRespInfo);
        } else if (retAts.getWrittenRdCount() == 0) {
            retAts.writeRespCode("0");
            retAts.writeRespInfo("交易为空");
        }
        retAts.writeEnd();
        return retAts;
    }
}
